<!DOCTYPE html>
<html CN>







<head>
	
	
	<link rel="stylesheet" href="/css/allinone.min.css"> 

	
	<!-- Global Site Tag (gtag.js) - Google Analytics -->
	<script async src="https://www.googletagmanager.com/gtag/js?id=UA-42863699-1"></script>
	<script>
		window.dataLayer = window.dataLayer || [];
		function gtag(){dataLayer.push(arguments);}
		gtag('js', new Date());
		gtag('config', 'UA-42863699-1');
	</script>
	

	<meta charset="utf-8" />
	<meta http-equiv="X-UA-Compatible" content="IE=edge" />

	<title>kubernetes 简介：service 和 kube-proxy 原理 | Cizixs Write Here</title>

	<meta name="HandheldFriendly" content="True" />
	<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
	<meta name="generator" content="hexo">
	<meta name="author" content="Cizixs Wu">
	<meta name="description" content="">

	
	<meta name="keywords" content="">
	

	
	<link rel="shortcut icon" href="https://cizixs-blog.oss-cn-beijing.aliyuncs.com/006tNc79ly1g1qxfovpzyj30740743yg.jpg">
	

	
	<meta name="theme-color" content="#3c484e">
	<meta name="msapplication-TileColor" content="#3c484e">
	

	

	

	<meta property="og:site_name" content="Cizixs Write Here">
	<meta property="og:type" content="article">
	<meta property="og:title" content="kubernetes 简介：service 和 kube-proxy 原理 | Cizixs Write Here">
	<meta property="og:description" content="">
	<meta property="og:url" content="http://cizixs.com/2017/03/30/kubernetes-introduction-service-and-kube-proxy/">

	
	<meta property="article:published_time" content="2017-03-30T00:03:00+08:00"/> 
	<meta property="article:author" content="Cizixs Wu">
	<meta property="article:published_first" content="Cizixs Write Here, /2017/03/30/kubernetes-introduction-service-and-kube-proxy/" />
	

	
	
	<script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
	

	
	<script src="https://cdn.staticfile.org/highlight.js/9.10.0/highlight.min.js"></script>
	

	
	
<link rel="stylesheet" href="/css/prism-base16-ateliersulphurpool.light.css" type="text/css"></head>
<body class="post-template">
    <div class="site-wrapper">
        




<header class="site-header outer" style="z-index: 999">
    <div class="inner">
        
<nav class="site-nav"> 
    <div class="site-nav-left">
        <ul class="nav">
            <li>
                
                <a href="/" title="Home">Home</a>
                
            </li>
            
            
            <li>
                <a href="/about" title="About">About</a>
            </li>
            
            <li>
                <a href="/archives" title="Archives">Archives</a>
            </li>
            
            
        </ul> 
    </div>
    <div class="site-nav-right">
        
<div class="social-links" >
    
    <a class="social-link" title="weibo" href="https://weibo.com/1921727853" target="_blank" rel="noopener">
        <svg viewBox="0 0 1141 1024" xmlns="http://www.w3.org/2000/svg"><path d="M916.48 518.144q27.648 21.504 38.912 51.712t9.216 62.976-14.336 65.536-31.744 59.392q-34.816 48.128-78.848 81.92t-91.136 56.32-94.72 35.328-89.6 18.944-75.264 7.68-51.712 1.536-49.152-2.56-68.096-10.24-78.336-21.504-79.872-36.352-74.24-55.296-59.904-78.848q-16.384-29.696-22.016-63.488t-5.632-86.016q0-22.528 7.68-51.2t27.136-63.488 53.248-75.776 86.016-90.112q51.2-48.128 105.984-85.504t117.248-57.856q28.672-10.24 63.488-11.264t57.344 11.264q10.24 11.264 19.456 23.04t12.288 29.184q3.072 14.336 0.512 27.648t-5.632 26.624-5.12 25.6 2.048 22.528q17.408 2.048 33.792-1.536t31.744-9.216 31.232-11.776 33.28-9.216q27.648-5.12 54.784-4.608t49.152 7.68 36.352 22.016 17.408 38.4q2.048 14.336-2.048 26.624t-8.704 23.04-7.168 22.016 1.536 23.552q3.072 7.168 14.848 13.312t27.136 12.288 32.256 13.312 29.184 16.384zM658.432 836.608q26.624-16.384 53.76-45.056t44.032-64 18.944-75.776-20.48-81.408q-19.456-33.792-47.616-57.344t-62.976-37.376-74.24-19.968-80.384-6.144q-78.848 0-139.776 16.384t-105.472 43.008-72.192 60.416-38.912 68.608q-11.264 33.792-6.656 67.072t20.992 62.976 42.496 53.248 57.856 37.888q58.368 25.6 119.296 32.256t116.224 0.512 100.864-21.504 74.24-33.792zM524.288 513.024q20.48 8.192 38.912 18.432t32.768 27.648q10.24 12.288 17.92 30.72t10.752 39.424 1.536 42.496-9.728 38.912q-8.192 18.432-19.968 37.376t-28.672 35.328-40.448 29.184-57.344 18.944q-61.44 11.264-117.76-11.264t-88.064-74.752q-12.288-39.936-13.312-70.656t16.384-66.56q13.312-27.648 40.448-51.712t62.464-38.912 75.264-17.408 78.848 12.8zM361.472 764.928q37.888 3.072 57.856-18.432t21.504-48.128-15.36-47.616-52.736-16.896q-27.648 3.072-43.008 23.552t-17.408 43.52 9.728 42.496 39.424 21.504zM780.288 6.144q74.752 0 139.776 19.968t113.664 57.856 76.288 92.16 27.648 122.88q0 33.792-16.384 50.688t-35.328 17.408-35.328-14.336-16.384-45.568q0-40.96-22.528-77.824t-59.392-64.512-84.48-43.52-96.768-15.872q-31.744 0-47.104-15.36t-14.336-34.304 18.944-34.304 51.712-15.36zM780.288 169.984q95.232 0 144.384 48.64t49.152 146.944q0 30.72-10.24 43.52t-22.528 11.264-22.528-14.848-10.24-35.84q0-60.416-34.816-96.256t-93.184-35.84q-19.456 0-28.672-10.752t-9.216-23.04 9.728-23.04 28.16-10.752z" /></svg>
    </a>
    

    
    <a class="social-link" title="github" href="https://github.com/cizixs" target="_blank" rel="noopener">
        <svg viewBox="0 0 1049 1024" xmlns="http://www.w3.org/2000/svg"><path d="M524.979332 0C234.676191 0 0 234.676191 0 524.979332c0 232.068678 150.366597 428.501342 358.967656 498.035028 26.075132 5.215026 35.636014-11.299224 35.636014-25.205961 0-12.168395-0.869171-53.888607-0.869171-97.347161-146.020741 31.290159-176.441729-62.580318-176.441729-62.580318-23.467619-60.841976-58.234462-76.487055-58.234463-76.487055-47.804409-32.15933 3.476684-32.15933 3.476685-32.15933 53.019436 3.476684 80.83291 53.888607 80.83291 53.888607 46.935238 79.963739 122.553122 57.365291 152.97411 43.458554 4.345855-33.897672 18.252593-57.365291 33.028501-70.402857-116.468925-12.168395-239.022047-57.365291-239.022047-259.012982 0-57.365291 20.860106-104.300529 53.888607-140.805715-5.215026-13.037566-23.467619-66.926173 5.215027-139.067372 0 0 44.327725-13.906737 144.282399 53.888607 41.720212-11.299224 86.917108-17.383422 131.244833-17.383422s89.524621 6.084198 131.244833 17.383422C756.178839 203.386032 800.506564 217.29277 800.506564 217.29277c28.682646 72.1412 10.430053 126.029806 5.215026 139.067372 33.897672 36.505185 53.888607 83.440424 53.888607 140.805715 0 201.64769-122.553122 245.975415-239.891218 259.012982 19.121764 16.514251 35.636014 47.804409 35.636015 97.347161 0 70.402857-0.869171 126.898978-0.869172 144.282399 0 13.906737 9.560882 30.420988 35.636015 25.205961 208.601059-69.533686 358.967656-265.96635 358.967655-498.035028C1049.958663 234.676191 814.413301 0 524.979332 0z" /></svg>
    </a>
    

    
    <a class="social-link" title="stackoverflow" href="https://stackoverflow.com/users/1925083/cizixs" target="_blank" rel="noopener">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M15 21h-10v-2h10v2zm6-11.665l-1.621-9.335-1.993.346 1.62 9.335 1.994-.346zm-5.964 6.937l-9.746-.975-.186 2.016 9.755.879.177-1.92zm.538-2.587l-9.276-2.608-.526 1.954 9.306 2.5.496-1.846zm1.204-2.413l-8.297-4.864-1.029 1.743 8.298 4.865 1.028-1.744zm1.866-1.467l-5.339-7.829-1.672 1.14 5.339 7.829 1.672-1.14zm-2.644 4.195v8h-12v-8h-2v10h16v-10h-2z"/></svg>
    </a>
    

    

    
    <a class="social-link" title="twitter" href="https://twitter.com/cizixs" target="_blank" rel="noopener">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M30.063 7.313c-.813 1.125-1.75 2.125-2.875 2.938v.75c0 1.563-.188 3.125-.688 4.625a15.088 15.088 0 0 1-2.063 4.438c-.875 1.438-2 2.688-3.25 3.813a15.015 15.015 0 0 1-4.625 2.563c-1.813.688-3.75 1-5.75 1-3.25 0-6.188-.875-8.875-2.625.438.063.875.125 1.375.125 2.688 0 5.063-.875 7.188-2.5-1.25 0-2.375-.375-3.375-1.125s-1.688-1.688-2.063-2.875c.438.063.813.125 1.125.125.5 0 1-.063 1.5-.25-1.313-.25-2.438-.938-3.313-1.938a5.673 5.673 0 0 1-1.313-3.688v-.063c.813.438 1.688.688 2.625.688a5.228 5.228 0 0 1-1.875-2c-.5-.875-.688-1.813-.688-2.75 0-1.063.25-2.063.75-2.938 1.438 1.75 3.188 3.188 5.25 4.25s4.313 1.688 6.688 1.813a5.579 5.579 0 0 1 1.5-5.438c1.125-1.125 2.5-1.688 4.125-1.688s3.063.625 4.188 1.813a11.48 11.48 0 0 0 3.688-1.375c-.438 1.375-1.313 2.438-2.563 3.188 1.125-.125 2.188-.438 3.313-.875z"/></svg>

    </a>
    

    
    <a class="social-link" title="instagram" href="https://www.instagram.com/cizixs/" target="_blank" rel="noopener">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z"/></svg>
    </a>
    
    
    
</div>
    </div>
</nav>
    </div>
</header>


<main id="site-main" class="site-main outer" role="main">
    <div class="inner">
        <header class="post-full-header">
            <section class="post-full-meta">
                <time  class="post-full-meta-date" datetime="2017-03-29T16:00:00.000Z" itemprop="datePublished">
                    2017-03-30
                </time>
                
                <span class="date-divider">/</span>
                
                <a href="/categories/blog/">blog</a>&nbsp;&nbsp;
                
                
            </section>
            <h1 class="post-full-title">kubernetes 简介：service 和 kube-proxy 原理</h1>
        </header>
        <article class="post-full no-image">
            
            <section class="post-full-content">
                <div id="lightgallery" class="markdown-body">
                    <h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>在 kubernetes 集群中，网络是非常基础也非常重要的一部分。对于大规模的节点和容器来说，要保证网络的连通性、网络转发的高效，同时能做的 ip 和 port 自动化分配和管理，并让用户用直观简单的方式来访问需要的应用，这是需要复杂且细致设计的。</p>
<p>kubernetes 在这方面下了很大的功夫，它通过 <code>service</code>、<code>dns</code>、<code>ingress</code> 等概念，解决了服务发现、负载均衡的问题，也大大简化了用户的使用和配置。</p>
<p>这篇文章就讲解如何配置 kubernetes 的网络，最终从集群内部和集群外部都能访问应用。</p>
<h2 id="跨主机网络配置：flannel"><a href="#跨主机网络配置：flannel" class="headerlink" title="跨主机网络配置：flannel"></a>跨主机网络配置：flannel</h2><p>一直以来，kubernetes 并没有专门的网络模块负责网络配置，它需要用户在主机上已经配置好网络。kubernetes 对网络的要求是：容器之间（包括同一台主机上的容器，和不同主机的容器）可以互相通信，容器和集群中所有的节点也能直接通信。</p>
<p>至于具体的网络方案，用户可以自己选择，目前使用比较多的是 flannel，因为它比较简单，而且刚好满足 kubernetes 对网络的要求。我们会使用 flannel vxlan 模式，具体的配置我在博客之前<a href="http://cizixs.com/2016/06/15/flannel-overlay-network">有文章介绍过</a>，这里不再赘述。</p>
<p>以后 kubernetes 网络的发展方向是希望通过插件的方式来集成不同的网络方案， <a href="https://kubernetes.io/docs/concepts/cluster-administration/network-plugins/#cni" target="_blank" rel="noopener">CNI</a> 就是这一努力的结果，flannel 也能够通过 CNI 插件的形式使用。</p>
<h2 id="kube-proxy-和-service"><a href="#kube-proxy-和-service" class="headerlink" title="kube-proxy 和 service"></a>kube-proxy 和 service</h2><p>配置好网络之后，集群是什么情况呢？我们可以创建 pod，也能通过 ReplicationController 来创建特定副本的 pod（这是更推荐也是生产上要使用的方法，即使某个 rc 中只有一个 pod 实例）。可以从集群中获取每个 pod ip 地址，然后也能在集群内部直接通过 <code>podIP:Port</code> 来获取对应的服务。</p>
<p>但是还有一个问题：<strong>pod 是经常变化的，每次更新 ip 地址都可能会发生变化</strong>，如果直接访问容器 ip 的话，会有很大的问题。而且进行扩展的时候，rc 中会有新的 pod 创建出来，出现新的 ip 地址，我们需要一种更灵活的方式来访问 pod 的服务。</p>
<h3 id="Service-和-cluster-IP"><a href="#Service-和-cluster-IP" class="headerlink" title="Service 和 cluster IP"></a>Service 和 cluster IP</h3><p>针对这个问题，kubernetes 的解决方案是“服务”（service），每个服务都一个固定的虚拟 ip（这个 ip 也被称为 cluster IP），自动并且动态地绑定后面的 pod，所有的网络请求直接访问服务 ip，服务会自动向后端做转发。Service 除了提供稳定的对外访问方式之外，还能起到负载均衡（Load Balance）的功能，自动把请求流量分布到后端所有的服务上，服务可以做到对客户透明地进行水平扩展（scale）。</p>
<p><img src="https://coreos.com/kubernetes/docs/latest/img/service.svg" alt=""></p>
<p>而实现 service 这一功能的关键，就是 kube-proxy。kube-proxy 运行在每个节点上，监听 API Server 中服务对象的变化，通过管理 iptables 来实现网络的转发。</p>
<blockquote>
<p><strong>NOTE</strong>: kube-proxy 要求 NODE 节点操作系统中要具备 /sys/module/br_netfilter 文件，而且还要设置 bridge-nf-call-iptables=1，如果不满足要求，那么 kube-proxy 只是将检查信息记录到日志中，kube-proxy 仍然会正常运行，但是这样通过 Kube-proxy 设置的某些 iptables 规则就不会工作。</p>
</blockquote>
<p>kube-proxy 有两种实现 service 的方案：userspace 和 iptables</p>
<ul>
<li>userspace 是在用户空间监听一个端口，所有的 service 都转发到这个端口，然后 kube-proxy 在内部应用层对其进行转发。因为是在用户空间进行转发，所以效率也不高</li>
<li>iptables 完全实现 iptables 来实现 service，是目前默认的方式，也是推荐的方式，效率很高（只有内核中 netfilter 一些损耗）。</li>
</ul>
<p>这篇文章通过 iptables 模式运行 kube-proxy，后面的分析也是针对这个模式的，userspace 只是旧版本支持的模式，以后可能会放弃维护和支持。</p>
<h3 id="kube-proxy-参数介绍"><a href="#kube-proxy-参数介绍" class="headerlink" title="kube-proxy 参数介绍"></a>kube-proxy 参数介绍</h3><p>kube-proxy 的功能相对简单一些，也比较独立，需要的配置并不是很多，比较常用的启动参数包括：</p>
<table>
<thead>
<tr>
<th>参数</th>
<th>含义</th>
<th>默认值</th>
</tr>
</thead>
<tbody>
<tr>
<td>–alsologtostderr</td>
<td>打印日志到标准输出</td>
<td>false</td>
</tr>
<tr>
<td>–bind-address</td>
<td>HTTP 监听地址</td>
<td>0.0.0.0</td>
</tr>
<tr>
<td>–cleanup-iptables</td>
<td>如果设置为 true，会清理 proxy 设置的 iptables 选项并退出</td>
<td>false</td>
</tr>
<tr>
<td>–healthz-bind-address</td>
<td>健康检查 HTTP API 监听端口</td>
<td>127.0.0.1</td>
</tr>
<tr>
<td>–healthz-port</td>
<td>健康检查端口</td>
<td>10249</td>
</tr>
<tr>
<td>–iptables-masquerade-bit</td>
<td>使用 iptables 进行 SNAT 的掩码长度</td>
<td>14</td>
</tr>
<tr>
<td>–iptables-sync-period</td>
<td>iptables 更新频率</td>
<td>30s</td>
</tr>
<tr>
<td>–kubeconfig</td>
<td>kubeconfig 配置文件地址</td>
<td></td>
</tr>
<tr>
<td>–log-dir</td>
<td>日志文件目录/路径</td>
<td></td>
</tr>
<tr>
<td>–masquerade-all</td>
<td>如果使用 iptables 模式，对所有流量进行 SNAT 处理</td>
<td>false</td>
</tr>
<tr>
<td>–master</td>
<td>kubernetes master API Server 地址</td>
<td></td>
</tr>
<tr>
<td>–proxy-mode</td>
<td>代理模式，<code>userspace</code> 或者 <code>iptables</code>， 目前默认是 <code>iptables</code>，如果系统或者 iptables 版本不够新，会 fallback 到 userspace 模式</td>
<td>iptables</td>
</tr>
<tr>
<td>–proxy-port-range</td>
<td>代理使用的端口范围， 格式为 <code>beginPort-endPort</code>，如果没有指定，会随机选择</td>
<td><code>0-0</code></td>
</tr>
<tr>
<td>–udp-timeout</td>
<td>UDP 空连接 timeout 时间，只对 <code>userspace</code> 模式有用</td>
<td>250ms</td>
</tr>
<tr>
<td>–v</td>
<td>日志级别</td>
<td>0</td>
</tr>
</tbody>
</table>
<p><code>kube-proxy</code> 的工作模式可以通过 <code>--proxy-mode</code> 进行配置，可以选择 <code>userspace</code> 或者 <code>iptables</code>。</p>
<h3 id="实例启动和测试"><a href="#实例启动和测试" class="headerlink" title="实例启动和测试"></a>实例启动和测试</h3><p>我们可以在终端上启动 <code>kube-proxy</code>，也可以使用诸如 <code>systemd</code> 这样的工具来管理它，比如下面就是一个简单的 <code>kube-proxy.service</code> 配置文件</p>
<pre><code>[root@localhost]# cat /usr/lib/systemd/system/kube-proxy.service
[Unit]
Description=Kubernetes Proxy Service
Documentation=http://kubernetes.com
After=network.target
Wants=network.target

[Service]
Type=simple
EnvironmentFile=-/etc/sysconfig/kube-proxy
ExecStart=/usr/bin/kube-proxy \
    --master=http://172.17.8.100:8080 \
    --v=4 \
    --proxy-mode=iptables
TimeoutStartSec=0
Restart=on-abnormal

[Install]
WantedBy=multi-user.target
</code></pre><p>为了方便测试，我们创建一个 rc，里面有三个 pod。这个 pod 运行的是 <a href="https://github.com/cizixs/whoami" target="_blank" rel="noopener"><code>cizixs/whoami</code> 容器</a>，它是一个简单的 HTTP 服务器，监听在 3000 端口，访问它会返回容器的 hostname。</p>
<pre class=" language-bash"><code class="language-bash"><span class="token punctuation">[</span>root@localhost ~<span class="token punctuation">]</span><span class="token comment" spellcheck="true"># cat whoami-rc.yml</span>
apiVersion: v1
kind: ReplicationController
metadata:
  name: <span class="token function">whoami</span>
spec:
  replicas: 3
  selector:
    app: <span class="token function">whoami</span>
  template:
    metadata:
      name: <span class="token function">whoami</span>
      labels:
        app: <span class="token function">whoami</span>
        env: dev
    spec:
      containers:
      - name: <span class="token function">whoami</span>
        image: cizixs/whoami:v0.5
        ports:
        - containerPort: 3000
        env:
          - name: MESSAGE
            value: viola
</code></pre>
<p>我们为每个 pod 设置了两个 label：<code>app=whoami</code> 和 <code>env=dev</code>，这两个标签很重要，也是后面服务进行绑定 pod 的关键。</p>
<p>为了使用 service，我们还要定义另外一个文件，并通过 <code>kubectl create -f ./whoami-svc.yml</code> 来创建出来对象：</p>
<pre class=" language-bash"><code class="language-bash">apiVersion: v1
kind: Service
metadata:
  labels:
    name: <span class="token function">whoami</span>
  name: <span class="token function">whoami</span>
spec:
  ports:
    - port: 3000
      targetPort: 3000
      protocol: TCP
  selector:
    app: <span class="token function">whoami</span>
    env: dev
</code></pre>
<p>其中 <code>selector</code> 告诉 kubernetes 这个 service 和后端哪些 pod 绑定在一起，这里包含的键值对会对所有 pod 的 <code>labels</code> 进行匹配，只要完全匹配，service 就会把 pod 作为后端。也就是说，service 和 rc 并不是对应的关系，一个 service 可能会使用多个 rc 管理的 pod 作为后端应用。</p>
<p><code>ports</code> 字段指定服务的端口信息：</p>
<ul>
<li><code>port</code>：虚拟 ip 要绑定的 port，每个 service 会创建出来一个虚拟 ip，通过访问 <code>vip:port</code> 就能获取服务的内容。这个 port 可以用户随机选取，因为每个服务都有自己的 vip，也不用担心冲突的情况</li>
<li><code>targetPort</code>：pod 中暴露出来的 port，这是运行的容器中具体暴露出来的端口，一定不能写错</li>
<li><code>protocol</code>：提供服务的协议类型，可以是 <code>TCP</code> 或者 <code>UDP</code></li>
</ul>
<p>创建之后可以列出 service ，发现我们创建的 service 已经分配了一个虚拟 ip (10.10.10.28)，这个虚拟 ip 地址是不会变化的（除非 service 被删除）。查看 service 的详情可以看到它的 endpoints 列出，对应了具体提供服务的 pod 地址和端口。</p>
<pre class=" language-bash"><code class="language-bash"><span class="token punctuation">[</span>root@localhost ~<span class="token punctuation">]</span><span class="token comment" spellcheck="true"># kubectl get svc</span>
NAME         CLUSTER-IP    EXTERNAL-IP   PORT<span class="token punctuation">(</span>S<span class="token punctuation">)</span>    AGE
kubernetes   10.10.10.1    <span class="token operator">&lt;</span>none<span class="token operator">></span>        443/TCP    19d
<span class="token function">whoami</span>       10.10.10.28   <span class="token operator">&lt;</span>none<span class="token operator">></span>        3000/TCP   1d

<span class="token punctuation">[</span>root@localhost ~<span class="token punctuation">]</span><span class="token comment" spellcheck="true"># kubectl describe svc whoami</span>
Name:                   <span class="token function">whoami</span>
Namespace:              default
Labels:                 name<span class="token operator">=</span>whoami
Selector:               app<span class="token operator">=</span>whoami
Type:                   ClusterIP
IP:                     10.10.10.28
Port:                   <span class="token operator">&lt;</span>unset<span class="token operator">></span> 3000/TCP
Endpoints:              10.11.32.6:3000,10.13.192.4:3000,10.16.192.3:3000
Session Affinity:       None
No events.
</code></pre>
<p>默认的 service 类型是 <code>ClusterIP</code>，这个也可以从上面输出看出来。在这种情况下，只能从集群内部访问这个 IP，不能直接从集群外部访问服务。如果想对外提供服务，我们后面会讲解决方案。</p>
<p>测试一下，访问 service 服务的时候可以看到它会随机地访问后端的 pod，给出不同的返回：</p>
<pre class=" language-bash"><code class="language-bash"><span class="token punctuation">[</span>root@localhost ~<span class="token punctuation">]</span><span class="token comment" spellcheck="true"># curl http://10.10.10.28:3000</span>
viola from whoami-8fpqp
<span class="token punctuation">[</span>root@localhost ~<span class="token punctuation">]</span><span class="token comment" spellcheck="true"># curl http://10.10.10.28:3000</span>
viola from whoami-c0x6h
<span class="token punctuation">[</span>root@localhost ~<span class="token punctuation">]</span><span class="token comment" spellcheck="true"># curl http://10.10.10.28:3000</span>
viola from whoami-8fpqp
<span class="token punctuation">[</span>root@localhost ~<span class="token punctuation">]</span><span class="token comment" spellcheck="true"># curl http://10.10.10.28:3000</span>
viola from whoami-dc9ds
</code></pre>
<p>默认情况下，服务会随机转发到可用的后端。如果希望保持会话（同一个 client 永远都转发到相同的 pod），可以把 <code>service.spec.sessionAffinity</code> 设置为 <code>ClientIP</code>。</p>
<p><strong>NOTE</strong>: 需要注意的是，服务分配的 cluster IP 是一个虚拟 ip，如果你尝试 <code>ping</code> 这个 IP 会发现它没有任何响应，这也是刚接触 kubernetes service 的人经常会犯的错误。实际上，这个虚拟 IP 只有和它的 port 一起的时候才有作用，直接访问它，或者想访问该 IP 的其他端口都是徒劳。</p>
<h3 id="外部能够访问的服务"><a href="#外部能够访问的服务" class="headerlink" title="外部能够访问的服务"></a>外部能够访问的服务</h3><p>上面创建的服务只能在集群内部访问，这在生产环境中还不能直接使用。如果希望有一个能直接对外使用的服务，可以使用 <code>NodePort</code> 或者 <code>LoadBalancer</code> 类型的 Service。我们先说说 <code>NodePort</code> ，它的意思是在所有 worker 节点上暴露一个端口，这样外部可以直接通过访问 <code>nodeIP:Port</code> 来访问应用。</p>
<p>我们先把刚才创建的服务删除：</p>
<pre class=" language-bash"><code class="language-bash"><span class="token punctuation">[</span>root@localhost ~<span class="token punctuation">]</span><span class="token comment" spellcheck="true"># kubectl delete rc whoami</span>
replicationcontroller <span class="token string">"whoami"</span> deleted

<span class="token punctuation">[</span>root@localhost ~<span class="token punctuation">]</span><span class="token comment" spellcheck="true"># kubectl delete svc whoami</span>
<span class="token function">service</span> <span class="token string">"whoami"</span> deleted

<span class="token punctuation">[</span>root@localhost ~<span class="token punctuation">]</span><span class="token comment" spellcheck="true"># kubectl get pods,svc,rc</span>
NAME         CLUSTER-IP   EXTERNAL-IP   PORT<span class="token punctuation">(</span>S<span class="token punctuation">)</span>   AGE
kubernetes   10.10.10.1   <span class="token operator">&lt;</span>none<span class="token operator">></span>        443/TCP   14h
</code></pre>
<p>对我们原来的 <code>Service</code> 配置文件进行修改，把 <code>spec.type</code> 写成 <code>NodePort</code> 类型：</p>
<pre class=" language-bash"><code class="language-bash"><span class="token punctuation">[</span>root@localhost ~<span class="token punctuation">]</span><span class="token comment" spellcheck="true"># cat whoami-svc.yml</span>
apiVersion: v1
kind: Service
metadata:
  labels:
    name: <span class="token function">whoami</span>
  name: <span class="token function">whoami</span>
spec:
  ports:
    - port: 3000
      protocol: TCP
      <span class="token comment" spellcheck="true"># nodePort: 31000</span>
  selector:
    app: <span class="token function">whoami</span>
  type: NodePort
</code></pre>
<p>因为我们的应用比较简单，只有一个端口。如果 pod 有多个端口，也可以在 <code>spec.ports</code>中继续添加，只有保证多个 port 之间不冲突就行。</p>
<p>重新创建 rc 和 svc：</p>
<pre class=" language-bash"><code class="language-bash"><span class="token punctuation">[</span>root@localhost ~<span class="token punctuation">]</span><span class="token comment" spellcheck="true"># kubectl create -f ./whoami-svc.yml</span>
<span class="token function">service</span> <span class="token string">"whoami"</span> created
<span class="token punctuation">[</span>root@localhost ~<span class="token punctuation">]</span><span class="token comment" spellcheck="true"># kubectl get rc,pods,svc</span>
NAME        DESIRED   CURRENT   READY     AGE
rc/whoami   3         3         3         10s

NAME              READY     STATUS    RESTARTS   AGE
po/whoami-8zc3d   1/1       Running   0          10s
po/whoami-mc2fg   1/1       Running   0          10s
po/whoami-z6skj   1/1       Running   0          10s

NAME             CLUSTER-IP     EXTERNAL-IP   PORT<span class="token punctuation">(</span>S<span class="token punctuation">)</span>          AGE
svc/kubernetes   10.10.10.1     <span class="token operator">&lt;</span>none<span class="token operator">></span>        443/TCP          14h
svc/whoami       10.10.10.163   <span class="token operator">&lt;</span>nodes<span class="token operator">></span>       3000:31647/TCP   7s
</code></pre>
<p>需要注意的是，因为我们没有指定 <code>nodePort</code> 的值，kubernetes 会自动给我们分配一个，比如这里的 <code>31647</code>（默认的取值范围是 30000-32767）。当然我们也可以删除配置中 <code># nodePort: 31000</code> 的注释，这样会使用 <code>31000</code> 端口。</p>
<p><code>nodePort</code> 类型的服务会在所有的 worker 节点（运行了 kube-proxy）上统一暴露出端口对外提供服务，也就是说外部可以任意选择一个节点进行访问。比如我本地集群有三个节点：<code>172.17.8.100</code>、<code>172.17.8.101</code> 和 <code>172.17.8.102</code>：</p>
<pre class=" language-bash"><code class="language-bash"><span class="token punctuation">[</span>root@localhost ~<span class="token punctuation">]</span><span class="token comment" spellcheck="true"># curl http://172.17.8.100:31647</span>
viola from whoami-mc2fg
<span class="token punctuation">[</span>root@localhost ~<span class="token punctuation">]</span><span class="token comment" spellcheck="true"># curl http://172.17.8.101:31647</span>
viola from whoami-8zc3d
<span class="token punctuation">[</span>root@localhost ~<span class="token punctuation">]</span><span class="token comment" spellcheck="true"># curl http://172.17.8.102:31647</span>
viola from whoami-z6skj
</code></pre>
<p>有了 <code>nodePort</code>，用户可以通过外部的 Load Balance 或者路由器把流量转发到任意的节点，对外提供服务的同时，也可以做到负载均衡的效果。</p>
<p><code>nodePort</code> 类型的服务并不影响原来虚拟 IP 的访问方式，内部节点依然可以通过 <code>vip:port</code> 的方式进行访问。</p>
<p><code>LoadBalancer</code> 类型的服务需要公有云支持，如果你的集群部署在公有云（GCE、AWS等）可以考虑这种方式。</p>
<h2 id="service-原理解析"><a href="#service-原理解析" class="headerlink" title="service 原理解析"></a>service 原理解析</h2><p>目前 kube-proxy 默认使用 iptables 模式，上述展现的 service 功能都是通过修改 iptables 实现的。</p>
<p>我们来看一下从主机上访问 <code>service:port</code> 的时候发生了什么（通过 <code>iptables-save</code> 命令打印出来当前机器上的 iptables 规则）。</p>
<p>所有发送出去的报文会进入 KUBE-SERVICES 进行处理</p>
<pre class=" language-bash"><code class="language-bash">*nat
-A OUTPUT -m comment --comment <span class="token string">"kubernetes service portals"</span> -j KUBE-SERVICES
</code></pre>
<p>KUBE-SERVICES 每条规则对应了一个 service，它告诉继续进入到某个具体的 service chain 进行处理，比如这里的 <code>KUBE-SVC-OQCLJJ5GLLNFY3XB</code></p>
<pre class=" language-bash"><code class="language-bash">-A KUBE-SERVICES -d 10.10.10.28/32 -p tcp -m comment --comment <span class="token string">"default/whoami: cluster IP"</span> -m tcp --dport 3000 -j KUBE-SVC-OQCLJJ5GLLNFY3XB
</code></pre>
<p>更具体的 chain 中定义了怎么转发到对应 endpoint 的规则，比如我们的 rc 有三个 pods，这里也就会生成三个规则。这里利用了 iptables 随机和概率转发的功能</p>
<pre class=" language-bash"><code class="language-bash">-A KUBE-SVC-OQCLJJ5GLLNFY3XB -m comment --comment <span class="token string">"default/whoami:"</span> -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-VN72UHNM6XOXLRPW
-A KUBE-SVC-OQCLJJ5GLLNFY3XB -m comment --comment <span class="token string">"default/whoami:"</span> -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-YXCSPWPTUFI5WI5Y
-A KUBE-SVC-OQCLJJ5GLLNFY3XB -m comment --comment <span class="token string">"default/whoami:"</span> -j KUBE-SEP-FN74S3YUBFMWHBLF
</code></pre>
<p>我们来看第一个 chain，这个 chain 有两个规则，第一个表示给报文打上 mark；第二个是进行 DNAT（修改报文的目的地址），转发到某个 pod 地址和端口。</p>
<pre class=" language-bash"><code class="language-bash">-A KUBE-SEP-VN72UHNM6XOXLRPW -s 10.11.32.6/32 -m comment --comment <span class="token string">"default/whoami:"</span> -j KUBE-MARK-MASQ
-A KUBE-SEP-VN72UHNM6XOXLRPW -p tcp -m comment --comment <span class="token string">"default/whoami:"</span> -m tcp -j DNAT --to-destination 10.11.32.6:3000
</code></pre>
<p>因为地址是发送出去的，报文会根据路由规则进行处理，后续的报文就是通过 flannel 的网络路径发送出去的。</p>
<p><code>nodePort</code> 类型的 service 原理也是类似的，在 <code>KUBE-SERVICES</code> chain 的最后，如果目标地址不是 VIP 则会通过 <code>KUBE-NODEPORTS</code> ：</p>
<pre class=" language-bash"><code class="language-bash">Chain KUBE-SERVICES <span class="token punctuation">(</span>2 references<span class="token punctuation">)</span>
 pkts bytes target     prot opt <span class="token keyword">in</span>     out     <span class="token function">source</span>               destination         
    0     0 KUBE-NODEPORTS  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes <span class="token function">service</span> nodeports<span class="token punctuation">;</span> NOTE: this must be the last rule <span class="token keyword">in</span> this chain */ ADDRTYPE match dst-type LOCAL
</code></pre>
<p>而 <code>KUBE-NODEPORTS</code> chain 和 <code>KUBE-SERVICES</code> chain 其他规则一样，都是转发到更具体的 <code>service</code> chain，然后转发到某个 pod 上面。</p>
<pre class=" language-bash"><code class="language-bash">-A KUBE-NODEPORTS -p tcp -m comment --comment <span class="token string">"default/whoami:"</span> -m tcp --dport 31647 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment <span class="token string">"default/whoami:"</span> -m tcp --dport 31647 -j KUBE-SVC-OQCLJJ5GLLNFY3XB
</code></pre>
<h2 id="不足之处"><a href="#不足之处" class="headerlink" title="不足之处"></a>不足之处</h2><p>看起来 service 是个完美的方案，可以解决服务访问的所有问题，但是 service 这个方案（iptables 模式）也有自己的缺点。</p>
<p>首先，如果转发的 pod 不能正常提供服务，它不会自动尝试另一个 pod，当然这个可以通过 <code>readiness probes</code> 来解决。每个 pod 都有一个健康检查的机制，当有 pod 健康状况有问题时，kube-proxy 会删除对应的转发规则。</p>
<p>另外，<code>nodePort</code> 类型的服务也无法添加 TLS 或者更复杂的报文路由机制。</p>
<h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul>
<li><a href="http://blog.csdn.net/horsefoot/article/details/51249161" target="_blank" rel="noopener">Kubernetes 1.2 如何使用 iptables</a></li>
<li><a href="https://kubernetes.io/docs/user-guide/services/" target="_blank" rel="noopener">Kubernetes User Guide: Service</a></li>
<li><a href="https://kubernetes.io/docs/user-guide/debugging-services/" target="_blank" rel="noopener">Kubernetes User Guide: Debugging Services</a></li>
<li><a href="http://containerops.org/2017/01/30/kubernetes-services-and-ingress-under-x-ray/" target="_blank" rel="noopener">Kubernetes Services and Ingress Under X-ray</a></li>
<li><a href="https://coreos.com/kubernetes/docs/latest/services.html" target="_blank" rel="noopener">CoreOS documentation: Overview of a Service</a></li>
</ul>

                </div>
            </section>
        </article>
    </div>
    
<nav class="pagination">
    
    
    <a class="prev-post" title="kube-proxy 源码解析" href="/2017/04/07/kube-proxy-source-code-analysis/">
        ← kube-proxy 源码解析
    </a>
    
    <span class="prev-next-post">•</span>
    
    <a class="next-post" title="编写 Dockerfile 的最佳实践" href="/2017/03/28/dockerfile-best-practice/">
        编写 Dockerfile 的最佳实践 →
    </a>
    
    
</nav>

    <div class="inner">
    <!-- Begin Mailchimp Signup Form -->
    <link href="//cdn-images.mailchimp.com/embedcode/classic-10_7.css" rel="stylesheet" type="text/css">
    <style type="text/css">
    	#mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; }
    	/* Add your own Mailchimp form style overrides in your site stylesheet or in this style block.
    	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
    </style>
    <div id="mc_embed_signup">
    <form action="https://cizixs.us7.list-manage.com/subscribe/post?u=2d561b8dea52d73a2e05e6dcb&amp;id=5c710f135b" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
        <div id="mc_embed_signup_scroll">
    	<h2>订阅本博客，第一时间收到文章更新</h2>
    <div class="indicates-required"><span class="asterisk">*</span> indicates required</div>
    <div class="mc-field-group">
    	<label for="mce-EMAIL">邮件地址  <span class="asterisk">*</span>
    </label>
    	<input type="email" value="" name="EMAIL" class="required email" id="mce-EMAIL">
    </div>
    	<div id="mce-responses" class="clear">
    		<div class="response" id="mce-error-response" style="display:none"></div>
    		<div class="response" id="mce-success-response" style="display:none"></div>
    	</div>    <!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups-->
        <div style="position: absolute; left: -5000px;" aria-hidden="true"><input type="text" name="b_2d561b8dea52d73a2e05e6dcb_5c710f135b" tabindex="-1" value=""></div>
        <div class="clear"><input type="submit" value="Subscribe" name="subscribe" id="mc-embedded-subscribe" class="button"></div>
        </div>
    </form>
    </div>
    <script type='text/javascript' src='//s3.amazonaws.com/downloads.mailchimp.com/js/mc-validate.js'></script><script type='text/javascript'>(function($) {window.fnames = new Array(); window.ftypes = new Array();fnames[0]='EMAIL';ftypes[0]='email';}(jQuery));var $mcj = jQuery.noConflict(true);</script>
    <!--End mc_embed_signup-->
    </div>

    <div class="inner">
        <div id="disqus_thread"></div>
    </div>

    
</main>

<div class="t-g-control">
    <div class="gotop">
        <svg class="icon" width="32px" height="32px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M793.024 710.272a32 32 0 1 0 45.952-44.544l-310.304-320a32 32 0 0 0-46.4 0.48l-297.696 320a32 32 0 0 0 46.848 43.584l274.752-295.328 286.848 295.808z" fill="#8a8a8a" /></svg>
    </div>
    <div class="toc-control">
        <svg class="icon toc-icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M779.776 480h-387.2a32 32 0 0 0 0 64h387.2a32 32 0 0 0 0-64M779.776 672h-387.2a32 32 0 0 0 0 64h387.2a32 32 0 0 0 0-64M256 288a32 32 0 1 0 0 64 32 32 0 0 0 0-64M392.576 352h387.2a32 32 0 0 0 0-64h-387.2a32 32 0 0 0 0 64M256 480a32 32 0 1 0 0 64 32 32 0 0 0 0-64M256 672a32 32 0 1 0 0 64 32 32 0 0 0 0-64" fill="#8a8a8a" /></svg>
        <svg class="icon toc-close" style="display: none;" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M512 960c-247.039484 0-448-200.960516-448-448S264.960516 64 512 64 960 264.960516 960 512 759.039484 960 512 960zM512 128.287273c-211.584464 0-383.712727 172.128262-383.712727 383.712727 0 211.551781 172.128262 383.712727 383.712727 383.712727 211.551781 0 383.712727-172.159226 383.712727-383.712727C895.712727 300.415536 723.551781 128.287273 512 128.287273z" fill="#8a8a8a" /><path d="M557.05545 513.376159l138.367639-136.864185c12.576374-12.416396 12.672705-32.671738 0.25631-45.248112s-32.704421-12.672705-45.248112-0.25631l-138.560301 137.024163-136.447897-136.864185c-12.512727-12.512727-32.735385-12.576374-45.248112-0.063647-12.512727 12.480043-12.54369 32.735385-0.063647 45.248112l136.255235 136.671523-137.376804 135.904314c-12.576374 12.447359-12.672705 32.671738-0.25631 45.248112 6.271845 6.335493 14.496116 9.504099 22.751351 9.504099 8.12794 0 16.25588-3.103239 22.496761-9.247789l137.567746-136.064292 138.687596 139.136568c6.240882 6.271845 14.432469 9.407768 22.65674 9.407768 8.191587 0 16.352211-3.135923 22.591372-9.34412 12.512727-12.480043 12.54369-32.704421 0.063647-45.248112L557.05545 513.376159z" fill="#8a8a8a" /></svg>
    </div>
    <div class="gobottom">
        <svg class="icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M231.424 346.208a32 32 0 0 0-46.848 43.584l297.696 320a32 32 0 0 0 46.4 0.48l310.304-320a32 32 0 1 0-45.952-44.544l-286.848 295.808-274.752-295.36z" fill="#8a8a8a" /></svg>
    </div>
</div>
<div class="toc-main" style="right: -100%">
    <div class="post-toc">
        <span>TOC</span>
        <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#简介"><span class="toc-text">简介</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#跨主机网络配置：flannel"><span class="toc-text">跨主机网络配置：flannel</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#kube-proxy-和-service"><span class="toc-text">kube-proxy 和 service</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#Service-和-cluster-IP"><span class="toc-text">Service 和 cluster IP</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#kube-proxy-参数介绍"><span class="toc-text">kube-proxy 参数介绍</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#实例启动和测试"><span class="toc-text">实例启动和测试</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#外部能够访问的服务"><span class="toc-text">外部能够访问的服务</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#service-原理解析"><span class="toc-text">service 原理解析</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#不足之处"><span class="toc-text">不足之处</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#参考资料"><span class="toc-text">参考资料</span></a></li></ol>
    </div>
</div>



        

<aside class="read-next outer">
    <div class="inner">
        <div class="read-next-feed">
            
            

<article class="read-next-card"  style="background-image: url(https://cizixs-blog.oss-cn-beijing.aliyuncs.com/006tNc79ly1g1qxcn9ft3j318w0txdo6.jpg)"  >
  <header class="read-next-card-header">
    <small class="read-next-card-header-sitetitle">&mdash; Cizixs Write Here &mdash;</small>
    <h3 class="read-next-card-header-title">Recent Posts</h3>
  </header>
  <div class="read-next-divider">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
      <path d="M13 14.5s2 3 5 3 5.5-2.463 5.5-5.5S21 6.5 18 6.5c-5 0-7 11-12 11C2.962 17.5.5 15.037.5 12S3 6.5 6 6.5s4.5 3.5 4.5 3.5"/>
    </svg>
  </div>
  <div class="read-next-card-content">
    <ul>
      
      
      
      <li>
        <a href="/2018/08/26/what-is-istio/">什么是 istio</a>
      </li>
      
      
      
      <li>
        <a href="/2018/08/25/knative-serverless-platform/">serverless 平台 knative 简介</a>
      </li>
      
      
      
      <li>
        <a href="/2018/06/25/kubernetes-resource-management/">kubernetes 资源管理概述</a>
      </li>
      
      
      
      <li>
        <a href="/2018/01/24/use-prometheus-and-grafana-to-monitor-linux-machine/">使用 promethues 和 grafana 监控自己的 linux 机器</a>
      </li>
      
      
      
      <li>
        <a href="/2018/01/13/linux-udp-packet-drop-debug/">linux 系统 UDP 丢包问题分析思路</a>
      </li>
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    </ul>
  </div>
  <footer class="read-next-card-footer">
    <a href="/archives">  MORE  → </a>
  </footer>
</article>


            
            
            
        </div>
    </div>
</aside>


<footer class="site-footer outer">

	<div class="site-footer-content inner">
		<section class="copyright">
			<a href="/" title="Cizixs Write Here">Cizixs Write Here</a>
			&copy; 2019
		</section>
		<nav class="site-footer-nav">
			
            <a href="https://hexo.io" title="Hexo" target="_blank" rel="noopener">Hexo</a>
            <a href="https://github.com/xzhih/hexo-theme-casper" title="Casper" target="_blank" rel="noopener">Casper</a>
        </nav>
    </div>
</footer>






<div class="floating-header" >
	<div class="floating-header-logo">
        <a href="/" title="Cizixs Write Here">
			
                <img src="https://cizixs-blog.oss-cn-beijing.aliyuncs.com/006tNc79ly1g1qxfovpzyj30740743yg.jpg" alt="Cizixs Write Here icon" />
			
            <span>Cizixs Write Here</span>
        </a>
    </div>
    <span class="floating-header-divider">&mdash;</span>
    <div class="floating-header-title">kubernetes 简介：service 和 kube-proxy 原理</div>
    <progress class="progress" value="0">
        <div class="progress-container">
            <span class="progress-bar"></span>
        </div>
    </progress>
</div>
<script>
   $(document).ready(function () {
    var progressBar = document.querySelector('progress');
    var header = document.querySelector('.floating-header');
    var title = document.querySelector('.post-full-title');
    var lastScrollY = window.scrollY;
    var lastWindowHeight = window.innerHeight;
    var lastDocumentHeight = $(document).height();
    var ticking = false;

    function onScroll() {
        lastScrollY = window.scrollY;
        requestTick();
    }
    function requestTick() {
        if (!ticking) {
            requestAnimationFrame(update);
        }
        ticking = true;
    }
    function update() {
        var rect = title.getBoundingClientRect();
        var trigger = rect.top + window.scrollY;
        var triggerOffset = title.offsetHeight + 35;
        var progressMax = lastDocumentHeight - lastWindowHeight;
            // show/hide floating header
            if (lastScrollY >= trigger + triggerOffset) {
                header.classList.add('floating-active');
            } else {
                header.classList.remove('floating-active');
            }
            progressBar.setAttribute('max', progressMax);
            progressBar.setAttribute('value', lastScrollY);
            ticking = false;
        }

        window.addEventListener('scroll', onScroll, {passive: true});
        update();

        // TOC
        var width = $('.toc-main').width();
        $('.toc-control').click(function () {
            if ($('.t-g-control').css('width')=="50px") {
                if ($('.t-g-control').css('right')=="0px") {
                    $('.t-g-control').animate({right: width}, "slow");
                    $('.toc-main').animate({right: 0}, "slow");
                    toc_icon()
                } else {
                    $('.t-g-control').animate({right: 0}, "slow");
                    $('.toc-main').animate({right: -width}, "slow");
                    toc_icon()
                }
            } else {
                if ($('.toc-main').css('right')=="0px") {
                    $('.toc-main').slideToggle("fast", toc_icon());
                } else {
                    $('.toc-main').css('right', '0px');
                    toc_icon()
                }
            }
        })

        function toc_icon() {
            if ($('.toc-icon').css('display')=="none") {
                $('.toc-close').hide();
                $('.toc-icon').show();
            } else {
                $('.toc-icon').hide();
                $('.toc-close').show();
            }
        }

        $('.gotop').click(function(){
            $('html,body').animate({scrollTop:$('.post-full-header').offset().top}, 800);
        });
        $('.gobottom').click(function () {
            $('html,body').animate({scrollTop:$('.pagination').offset().top}, 800);
        });

        // highlight
        // https://highlightjs.org
        $('pre code').each(function(i, block) {
            hljs.highlightBlock(block);
        });
        $('td.code').each(function(i, block) {
            hljs.highlightBlock(block);
        });

        console.log("this theme is from https://github.com/xzhih/hexo-theme-casper")
    });
</script>



<link rel="stylesheet" href="https://cdn.staticfile.org/lightgallery/1.3.9/css/lightgallery.min.css">



<script src="https://cdn.staticfile.org/lightgallery/1.3.9/js/lightgallery.min.js"></script>


<script>
	$(function () {
		var postImg = $('#lightgallery').find('img');
		postImg.addClass('post-img');
		postImg.each(function () {
			var imgSrc = $(this).attr('src');
			$(this).attr('data-src', imgSrc);
		});
		$('#lightgallery').lightGallery({selector: '.post-img'});
	});
</script>



<script>

/**
*  RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
*  LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables*/

var disqus_config = function () {
this.page.url = 'http://cizixs.com/2017/03/30/kubernetes-introduction-service-and-kube-proxy/';  // Replace PAGE_URL with your page's canonical URL variable
this.page.identifier = 'http://cizixs.com/2017/03/30/kubernetes-introduction-service-and-kube-proxy/'; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
};

(function() { // DON'T EDIT BELOW THIS LINE
var d = document, s = d.createElement('script');
s.src = 'https://cizixs.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
                            


    </div>
</body>
</html>
